// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0

import { Palette } from "std-widgets.slint";
import { Api, PreviewData, PreviewDataKind, PropertyValue, PropertyValueKind, PropertyValueTable } from "../api.slint";
import { StatusLineApi } from "../components/status-line.slint";
import { EditorSizeSettings, Icons, EditorSpaceSettings } from "../components/styling.slint";
import { PropertyValueWidget } from "../components/property-widgets.slint";
import { TableData } from "../windowglobal.slint";
import { NameLabel } from "widgets/basics.slint";

export struct CellData {
    property-group-id: string,
    property-name: string,

    row: int,
    col: int,

    x: length,
    y: length,
    width: length,
    height: length}

export component EditWindow inherits PopupWindow {
    close-policy: close-on-click-outside;

    callback test(string) -> bool;
    callback save(string);
    callback close-editor();

    in property <CellData> current-cell-data;
    in-out property <PropertyValueTable> current-table;
    in property <PreviewData> preview-data;
    in property <string> property-container-id;

    function is-brush(property-value: PropertyValue) -> bool {
        return property-value.kind == PropertyValueKind.brush || property-value.kind == PropertyValueKind.color;
    }

    content := Rectangle {
        changed height => {
            parent.height = self.height;
        }

        drop-shadow-blur: 10px;
        drop-shadow-color: black.transparentize(0.5);
        drop-shadow-offset-x: 0;
        drop-shadow-offset-y: 0;
        border-radius: EditorSizeSettings.radius;
        width: is-brush(root.current-table.values[root.current-cell-data.row][root.current-cell-data.col]) ? 260px : self.preferred-width;
        height: self.preferred-height;
        background: Palette.alternate-background;

        hl := HorizontalLayout {
            padding: EditorSpaceSettings.default-padding;
            padding-left: EditorSpaceSettings.default-padding;
            width: is-brush(root.current-table.values[root.current-cell-data.row][root.current-cell-data.col]) ? 220px : self.preferred-width;

            NameLabel {
                property-name: pvw.property-name;
                property-value: pvw.property-value;
            }

            pvw := PropertyValueWidget {
                property-value: root.current-table.values[root.current-cell-data.row][root.current-cell-data.col];
                property-name: root.current-table.headers[root.current-cell-data.col];
                enabled: true;

                changed property-value => {
                    root.current-table.values[root.current-cell-data.row][root.current-cell-data.col] = self.property-value;
                }

                set-current-item() => {
                    TableData.show-brush-editor(root.current-cell-data.row, root.current-cell-data.col);
                    close-editor();
                }

                update-display-string(value) => {
                    root.current-table.values[root.current-cell-data.row][root.current-cell-data.col].display-string = value;
                }

                test-color-binding(text) => {
                    return root.test("\"\{text}\"");
                }
                test-brush-binding(kind, angle, color, stops) => {
                    return root.test(Api.as-json-brush(kind, angle, color, stops));
                }
                test-float-binding(text, unit) => {
                    return root.test(text);
                }
                test-code-binding(text) => {
                    return root.test(text);
                }
                test-string-binding(text, is_translated) => {
                    return root.test(is_translated ? "\"\{text}\"" : text);
                }

                set-bool-binding(value) => {
                    root.save(value ? "true" : "false");
                }
                set-color-binding(text) => {
                    root.save("\"\{text}\"");
                }
                set-brush-binding(kind, angle, color, stops) => {
                    root.save(Api.as-json-brush(kind, angle, color, stops));
                }
                set-float-binding(text, _unit) => {
                    root.save(text);
                }
                set-code-binding(text) => {
                    root.save(text);
                }
                set-string-binding(text, is_translated) => {
                    root.save(is_translated ? "\"\{text}\"" : text);
                }
                set-enum-binding(text) => {
                    root.save("\"\{text}\"");
                }
            }
        }
    }
}

component RowMarker inherits Rectangle {
    in property <int> value;
    in property <bool> header: false;
    in property <bool> hovered;
    in property <bool> show-menu: true;
    width: 30px;

    if (value > 0):   Rectangle {
        height: 30px;
        background: header ? transparent : Palette.alternate-background;
        VerticalLayout {
            HorizontalLayout {
                Text {
                    vertical-alignment: center;
                    horizontal-alignment: right;
                    text: value;
                }

                VerticalLayout {
                    alignment: LayoutAlignment.center;
                    padding: EditorSpaceSettings.default-padding / 4;

                    indicator := Image {
                        visible: hovered && show-menu;
                        colorize: Palette.foreground;
                        source: Icons.chevron-down;
                        width: 10px;
                        height: 10px;
                    }
                }
            }

            Rectangle {
                height: 1px;
                background: Palette.border;
                width: 100%;
            }
        }
    }
}

component Cell inherits Rectangle {
    in property <PropertyValue> property-value;

    in property <bool> is-header: false;
    in property <bool> is-writeable: false;

    in property <string> text;

    in-out property <color> bg-color: cell-clicked ? Palette.accent-background.transparentize(0.8) : transparent;

    private property <bool> cell-clicked: false;

    callback edit-clicked();

    width: 100px;
    height: 30px;
    border-width: 1px;
    border-color: Palette.border;
    background: is-header ? Palette.foreground.transparentize(0.9) : bg-color;

    HorizontalLayout {
        Rectangle {
            width: EditorSpaceSettings.default-padding / 2;
        }

        Text {
            font-weight: is-header ? 700 : 400;
            width: root.width - EditorSpaceSettings.default-padding;
            height: root.height;
            horizontal-alignment: TextHorizontalAlignment.left;
            vertical-alignment: center;
            overflow: TextOverflow.elide;
            text: root.text;
        }
    }

    if is-writeable: TouchArea {
        clicked => {
            root.edit-clicked();
        }
    }
}

export component Spreadsheet {
    in property <string> property-group-id;
    in property <PreviewData> preview-data: {
        name: "Addresses",
        has-getter: true,
        has-setter: true,
        kind: PreviewDataKind.Table,
    };
    in-out property <PropertyValueTable> current-table: {
        is-array: true,
        headers: ["type", "street", "city", "state", "zip", "favorite", "color"],
        values: [
            [
                { kind: PropertyValueKind.string, display-string: "home" },
                { kind: PropertyValueKind.string, display-string: "123 Oak Lane" },
                { kind: PropertyValueKind.string, display-string: "Richmond" },
                { kind: PropertyValueKind.string, display-string: "VA" },
                { kind: PropertyValueKind.string, display-string: "23226" },
                { kind: PropertyValueKind.boolean, value-bool: true, display-string: "true" },
                { kind: PropertyValueKind.color, display-string: "#ff0000" }
            ],
            [
                { kind: PropertyValueKind.string, display-string: "work" },
                { kind: PropertyValueKind.string, display-string: "456 Corporate Blvd" },
                { kind: PropertyValueKind.string, display-string: "Richmond" },
                { kind: PropertyValueKind.string, display-string: "VA" },
                { kind: PropertyValueKind.string, display-string: "23219" },
                { kind: PropertyValueKind.boolean, value-bool: false, display-string: "false" }
            ],
            [
                { kind: PropertyValueKind.string, display-string: "world" },
                { kind: PropertyValueKind.string, display-string: "456 Corporate Blvd" },
                { kind: PropertyValueKind.string, display-string: "Richmond" },
                { kind: PropertyValueKind.string, display-string: "VA" },
                { kind: PropertyValueKind.string, display-string: "23219" },
                { kind: PropertyValueKind.boolean, value-bool: false, display-string: "false" },
                { kind: PropertyValueKind.color, display-string: "#ff0000" }
            ]
        ],
    };

    private property <length> selection-x;
    private property <length> selection-y;

    private property <CellData> current-cell-data;

    VerticalLayout {
        HorizontalLayout {
            RowMarker { }

            for header in root.current-table.headers: Cell {
                is-header: true;
                text: header;
            }
        }

        for data-row[row] in root.current-table.values: HorizontalLayout {
            RowMarker {
                value: row + 1;
                hovered: ta.has-hover;
                show-menu: root.current-table.is-array;

                ta := TouchArea {
                    enabled: root.current-table.is-array;
                    clicked => {
                        root.selection-x = self.x;
                        root.selection-y = self.y;
                        row_menu.row-number = row;
                        row_menu.show({
                            x:self.mouse-x + ta.absolute-position.x - row_menu.absolute-position.x,
                            y:self.mouse-y + ta.absolute-position.y - row_menu.absolute-position.y
                        });
                    }
                }
            }

            for value[col] in data-row: Cell {
                text: value.display-string;
                is-writeable: true;

                edit-clicked() => {
                    root.current-cell-data = {
                        property-group-id: root.property-group-id,
                        property-name: preview-data.name,
                        property-value: root.current-table.values[row][col],
                        row: row,
                        col: col,
                        x: self.x,
                        y: parent.y,
                        width: self.width,
                        height: self.height
                    };
                    ew.show();
                }
            }
        }
    }

    ew := EditWindow {
        x: self.current-cell-data.x > 15px ? self.current-cell-data.x - EditorSpaceSettings.default-padding - 15px : (self.current-cell-data.x + self.current-cell-data.width > root.width ? root.width - ew.width : 0); // TODO the end needs to be windowWidth - current-cell.x < current.cell.width * 2;
        y: self.current-cell-data.y - EditorSpaceSettings.default-padding;
        current-cell-data <=> root.current-cell-data;
        current-table: root.current-table;
        preview-data <=> root.preview-data;
        property-container-id <=> property-group-id;

        private property <string> possible-error;

        function edit(new-value: string) -> bool {
            self.current-table.values[self.current-cell-data.row][self.current-cell-data.col].was-edited = true;
            self.current-table.values[self.current-cell-data.row][self.current-cell-data.col].edited-value = new-value;

            self.possible_error = Api.set-property-value-table(root.property-group-id, root.preview-data.name, root.current-table.values, root.current-table.is-array);
            StatusLineApi.help-text = self.possible-error;
            if self.possible-error == "" {
                TableData.populate-table(root.property-group-id, root.preview-data);
            }
            return self.possible-error == "";
        }

        test(new-value) => {
            return edit(new-value);
        }

        save(new-value) => {
            edit(new-value);
            self.close-editor();
        }

        close-editor => {
            self.close();
        }
    }

    row_menu := ContextMenuArea {
        in-out property <int> row-number;
        enabled: false;

        Menu {
            MenuItem {
                title: "Add Row Above";
                activated() => {
                    Api.insert-row-into-value-table(root.current_table, row_menu.row-number);
                }
            }

            MenuItem {
                title: "Add Row Below";
                activated() => {
                    Api.insert-row-into-value-table(root.current_table, row_menu.row-number + 1);
                }
            }

            MenuItem {
                title: "Remove Row";
                activated() => {
                    Api.remove-row-from-value-table(root.current_table, row_menu.row-number);
                }
            }
        }
    }
}
